/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package rentcalculator.controller;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import rentcalculator.model.Absence;
import rentcalculator.model.Algorithm;
import rentcalculator.model.Bill;
import rentcalculator.model.Charge;
import rentcalculator.model.Lodgement;
import rentcalculator.persist.LodgementDao;
import rentcalculator.util.DateUtil;

/**
 *
 * @author developer
 */
public class BillCalculatorImpl implements BillCalculator{

    //don't consider discount at the moment
    @Override
    public List<Charge> compute(Bill bill, Algorithm algorithm) {
        final List<Lodgement> renters = new LodgementDao().findRentersByFacilityId(
                bill.getFacility().getId(),bill.getStart(), null);
        boolean absentFree = bill.getFacility().isAbsentfree();
        List<Charge> charges = new ArrayList<>();
        double totalDays = 0;
        Iterator<Lodgement> iterTotal = renters.iterator();
        while(iterTotal.hasNext()){
            totalDays += getActualRentDays(iterTotal.next(),absentFree, bill);
        }
        
        Iterator<Lodgement> iterEach = renters.iterator();
        while(iterEach.hasNext()){
            Lodgement l = iterEach.next();
            Charge c = new Charge();
            c.setAlgorithm(algorithm);
            c.setBill(bill);
            c.setPerson(l.getPerson());
            c.setFee((getActualRentDays(l,absentFree,bill))/totalDays*bill.getPrice());
            charges.add(c);
        }
        
        
        
        
        return charges;
    }
    
    private long getActualRentDays(final Lodgement renter, final boolean absentFree, final Bill bill){
        Date rentEnd;
        if (renter.getEnd() == null) rentEnd =  bill.getEnd();
        else rentEnd = renter.getEnd();
        
        if(absentFree == false){
            return getBillableDays( renter.getStart(), rentEnd,
                bill.getStart(), bill.getEnd());
        }
        
        long totalAbsentDays = 0;
        Iterator<Absence> iter = renter.getAbsences().iterator();
        while(iter.hasNext()){
            
            Absence ab = iter.next();
            Date absentEnd = ab.getEnd();
            if(absentEnd == null) absentEnd = bill.getEnd();
            totalAbsentDays += getBillableDays(ab.getStart(),absentEnd,bill.getStart(),bill.getEnd());
        }
        
        return getBillableDays(renter.getStart(),rentEnd, bill.getStart(), bill.getEnd()) - totalAbsentDays;
        
    }
    
    /**
     * get the number of days during the bill. 
     * @param start
     * @param end
     * @param billStart
     * @param billEnd
     * @return the number of billable days
     */
    private long getBillableDays(Date start, Date end, Date billStart, Date billEnd){
        if( end.before(billStart) || start.after(billEnd)) return 0;
        Date tmpStartDate;
        Date tmpEndDate;
        
        if(start.after(billStart)){
            tmpStartDate = start;
        }else{
            tmpStartDate = billStart;
        }
        
        if(end.before(billEnd)){
            tmpEndDate = end;
        }else{
            tmpEndDate = billEnd;
        }
        
        return DateUtil.days(tmpEndDate, tmpStartDate);
        
        
    }
    
    
    public static void main(String[] args) throws Exception{
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        BillCalculatorImpl b = new BillCalculatorImpl();
        
        //one day 
        System.out.println(
                b.getBillableDays(
                        sdf.parse("2014-01-04"),
                        sdf.parse("2014-01-09"),
                        sdf.parse("2012-01-01"),
                        sdf.parse("2014-01-03"))     
        );
    }
    
}
